#include     <fcntl.h>      /*文件控制定义*/
#include     <termios.h>    /*PPSIX 终端控制定义*/
#include     <stdlib.h>
#include <unistd.h>
#include     <stdio.h>
#include     <errno.h>      /*错误号定义*/

#include "ComConfig.h"

#define FALSE   0

/**
 * *@brief  设置串口通信速率
 * *@param  fd     类型 int  打开串口的文件句柄
 * *@param  speed  类型 int  串口速度
 * *@return  void
 * */

int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,
    B38400, B19200, B9600, B4800, B2400, B1200, B300, B115200};
int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300, 38400,  
    19200,  9600, 4800, 2400, 1200,  300, 115200};

void set_speed(int fd, int speed)
{
    int   i; 
    int   status; 
    struct termios   Opt;
    if( 0 != tcgetattr(fd, &Opt) )
    {
        perror("set_speed");
        return ;
    }
    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) 
    { 
        if  (speed == name_arr[i]) 
        {     
            tcflush(fd, TCIOFLUSH);     
            cfsetispeed(&Opt, speed_arr[i]);  
            cfsetospeed(&Opt, speed_arr[i]);   
            status = tcsetattr(fd, TCSANOW, &Opt);  
            if  (status != 0) 
            {        
                perror("set_speed fd1");  
                return;     
            }    
            tcflush(fd,TCIOFLUSH);   
        }  
    }
}


/**
 * *@brief   设置串口数据位，停止位和效验位
 * *@param  fd     类型  int  打开的串口文件句柄
 * *@param  databits 类型  int 数据位   取值 为 7 或者8
 * *@param  stopbits 类型  int 停止位   取值为 1 或者2
 * *@param  parity  类型  int  效验类型 取值为N,E,O,,S
 * */
int set_Parity(int fd,int databits,int stopbits,int parity)
{ 
    struct termios options; 
    if  ( tcgetattr( fd,&options)  !=  0) { 
        perror("SetupSerial 1");     
        return(FALSE);  
    }
    options.c_cflag &= ~CSIZE; 
    switch (databits) /*设置数据位数*/
    {   
        case 7:     
            options.c_cflag |= CS7; 
            break;
        case 8:     
            options.c_cflag |= CS8;
            break;   
        default:    
            fprintf(stderr,"Unsupported data size\n"); return (FALSE);  
    }
    switch (parity) 
    {   
        case 'n':
        case 'N':    
            options.c_cflag &= ~PARENB;   /* Clear parity enable */
            options.c_iflag &= ~INPCK;     /* Enable parity checking */ 
            options.c_iflag |= IGNPAR;    /* ignore parity checking */
            break;  
        case 'o':   
        case 'O':     
            options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/  
            options.c_iflag |= INPCK;             /* Disnable parity checking */ 
            break;  
        case 'e':  
        case 'E':   
            options.c_cflag |= PARENB;     /* Enable parity */    
            options.c_cflag &= ~PARODD;   /* 转换为偶效验*/     
            //options.c_iflag |= INPCK;       /* Disnable parity checking */
            break;
        case 'S': 
        case 's':  /*as no parity*/   
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSIZE;
            options.c_cflag |= CS8; 
            break;  
        default:   
            fprintf(stderr,"Unsupported parity\n");    
            return (FALSE);  
    }  
    /* 设置停止位*/  
    switch (stopbits)
    {   
        case 1:    
            options.c_cflag &= ~CSTOPB;  
            break;  
        case 2:    
            options.c_cflag |= CSTOPB;  
            break;
        default:    
            fprintf(stderr,"Unsupported stop bits\n");  
            return (FALSE); 
    } 
    /* Set input parity option */ 
    if ( parity == 'e' | parity == 'E' | parity == 'o' | parity == 'O' )   
        options.c_iflag |= ( INPCK | ISTRIP ); 
    tcflush(fd,TCIFLUSH);
//    options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/   
//    options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
 

    //*******************************************************************************
    //Processed output is selected by setting the OPOST option in the c_oflag member:
    //options.c_oflag |= OPOST;
    //Raw output is selected by resetting the OPOST option in the c_oflag member:
    //
    //options.c_oflag &= ~OPOST;
    //When the OPOST option is disabled, all other option bits in c_oflag are ignored.
    options.c_oflag &= ~OPOST;


    //Raw input is unprocessed. Input characters are passed through exactly as they are received, when they are received. 
    //Generally you'll deselect the ICANON, ECHO, ECHOE, and ISIG options when using raw input:
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    //  To disable software flow control simply mask those bits:
    options.c_iflag &= ~(IXON | IXOFF | IXANY);    //添加的

    //  To disable hardware flow control
    options.c_cflag &= ~CRTSCTS;

    options.c_cflag |= (CLOCAL | CREAD);  

    //输入输出都不转换 .
    options.c_oflag &= ~(ONLCR | OCRNL);    //添加的
    options.c_iflag &= ~(ICRNL | INLCR);

    
    tcflush(fd, TCIOFLUSH);

    if (tcsetattr(fd,TCSANOW,&options) != 0)   
    { 
        perror("SetupSerial 3");   
        return (FALSE);  
    } 
    return (TRUE);  
}

int setVtimeVmin( int fd, unsigned Vtime, unsigned Vmin, unsigned *rVtime, unsigned *rVmin )
{

    struct termios options; 
    if  ( tcgetattr( fd,&options)  !=  0) 
    { 
        perror("SetupSerial 1");     
        return(FALSE);  
    }

    if( rVtime != NULL )
        *rVtime = options.c_cc[VTIME];
    if( rVmin != NULL )
        *rVmin  = options.c_cc[VMIN];

    options.c_cc[VTIME] = Vtime;
    options.c_cc[VMIN]  = Vmin;

    if (tcsetattr(fd,TCSANOW,&options) != 0)   
    { 
        perror("SetupSerial 3");   
        return (FALSE);  
    } 
    return (TRUE);  
}



